import { Provide, Inject, Config, httpError } from '@midwayjs/core';
import { ApiDingtalk } from '../utils/api.dingtalk';
import { AuthCenterConfigModel } from '../entity/auth_center_config.method';
import { CustomIdUtils } from "../utils/customId";
import { RedisService } from '@midwayjs/redis';
import { JsonConfigModel } from '../entity/json_config.method'
import { HttpService } from '@midwayjs/axios';

@Provide()
export class AuthCenterConfigService {

  @Config('dingtalkAuthConfig')
  dingtalkAuthConfig: any;

  @Config('appConfig')
  appConfig: any;

  @Inject()
  ApiDingtalk: ApiDingtalk;

  @Inject()
  AuthCenterConfigModel: AuthCenterConfigModel;

  @Inject()
  RedisService: RedisService;

  @Inject()
  CustomIdUtils: CustomIdUtils

  @Inject()
  httpService: HttpService

  @Inject()
  JsonConfigModel: JsonConfigModel

  /**
   * 钉钉OAuth登录授权页面链接获取
   * 文档地址：https://open.dingtalk.com/document/isvapp-server/obtain-identity-credentials
   * redirect_uri     授权通过/拒绝后回调地址。
   * response_type    固定值为code。授权通过后返回appCode。
   * client_id    appkey
   * scope    openid：授权后可获得用户userid  openid corpid：授权后可获得用户id和登录过程中用户选择的组织id，空格分隔。注意url编码。
   * state    跟随appCode原样返回。
   * prompt   值为consent时，会进入授权确认页。
   * @returns 
   */
  async getDingTalkAuthUri(state: string): Promise<any> {
    const authInfo = await this.AuthCenterConfigModel.getDataByCode(state);
    if (!authInfo || !authInfo[0]) throw new httpError.BadRequestError('授权回调信息不存在');
    const auth_uri = this.dingtalkAuthConfig.mf_auth_base;
    const url = `${this.dingtalkAuthConfig.login_uri}?redirect_uri=${encodeURIComponent(auth_uri)}&response_type=code&client_id=${this.appConfig.appKey}&scope=openid&state=${state}&prompt=consent`;
    return url;
  }

  /**
   * code换取token，并获取用户信息，之后回传用户信息给指定系统的接口
   * @param param0.authCode
   * @param param0.state
   * @returns 
   */
  async getUserAccessToken({ authCode, state }: { authCode: string, state: any }): Promise<any> {
    //  查询当前授权回调请求信息
    const authInfo = await this.AuthCenterConfigModel.getDataByCode(state);
    if (!authInfo || !authInfo[0]) throw new httpError.BadRequestError('授权回调信息不存在');

    //  获取用户钉钉授权token
    const tokenData = await this.ApiDingtalk.userAccessToken(this.appConfig.appKey, authCode, this.appConfig.appSecret);
    if (!tokenData.success || !tokenData.accessToken) throw new httpError.BadRequestError(tokenData);

    const _expiresTime = Date.now() + tokenData.expireIn;

    //  获取用户通讯录个人信息
    const userData = await this.ApiDingtalk.contactUsers(tokenData.accessToken);
    if (!userData.success) throw new httpError.BadRequestError(userData);

    //  查询当前用户是否是上海莫凡的在职员工
    const userList = await this.getOnJobUserLists();
    if(!userList.length) throw new httpError.BadRequestError("获取员工信息失败");
    if(!userList.includes(userData.unionId)) throw new httpError.BadRequestError("您不是当前组织的在职员工");

    // 回传用户信息
    const { callback_url } = authInfo[0];
    const _code = this.CustomIdUtils.customId({
      key1: userData.unionId,
      key2: Date.now() + "",
      key3: state,
      lowerCase: true
    });
    const dd_code = `dd:${_code}`;
    const _userData = {
      appCode: state,
      nick: userData.nick,
      unionId: userData.unionId,
      openId: userData.openId,
      avatarUrl: userData.avatarUrl || "",
      expiresTime: _expiresTime,
      accessToken: tokenData.accessToken,
      refreshToken: tokenData.refreshToken,
      code: dd_code
    }
    //  存储用户授权记录到redis
    await this.RedisService.set(dd_code, JSON.stringify(_userData), 'EX', 900);
    return {
      redirect: `${callback_url}?code=${dd_code}&app_code=${state}`
    };
  }

  /**
   * 授权完成 获取用户信息
   * @param code 
   */
  async getUserData(code: string) {
    // redis查询用户授权数据
    const userRes = await this.RedisService.get(code);
    if (userRes) {
      //  redis删除当前数据
      await this.RedisService.del(code);
      return JSON.parse(userRes);
    } else {
      throw new httpError.BadRequestError('授权信息不存在');
    }
  }

  /**
   * 新增数据
   * @param {*} appName
   * @param {*} callbackUrl
   * @returns 
   */
  async insertAuth({ appName, callbackUrl }: { appName: string, callbackUrl: string }): Promise<any> {
    const appCode = this.CustomIdUtils.customId({
      key1: appName,
      key2: callbackUrl,
      key3: Date.now() + ""
    });
    return await this.AuthCenterConfigModel.insert({ appName, appCode, callbackUrl });
  }

  /**
   * 授权信息分页查询
   * @param {*} pageSize 
   * @param {*} pageNum 
   * @param {*} searchKey 
   */
  async getAuthPages({ pageSize, pageNum, searchKey }: { pageSize: number, pageNum: number, searchKey: any }): Promise<any> {

    const total = await this.AuthCenterConfigModel.getTotalNum(searchKey);
    const res = {
      total: total[0].num,
      lists: []
    }

    if (total[0].num) {
      const resList = await this.AuthCenterConfigModel.getDataByPage(pageNum, pageSize, searchKey);
      resList.forEach((item: any) => {
        item.auth_uri = `${this.dingtalkAuthConfig.mf_auth_base}?code=${item.app_code}`;
      })
      res.lists = resList;
    }
    return res
  }

  /**
   * 更新数据
   * @param {*} id 
   * @param {*} appName 
   * @param {*} callbackUrl
   * @returns 
   */
  async updateAuth({ id, appName, callbackUrl }: { id: number, appName: string, callbackUrl: string }): Promise<any> {
    return await this.AuthCenterConfigModel.updateTokenById({ id, appName, callbackUrl });
  }

  /**
   * 删除数据
   * @param {*} id
   * @returns 
   */
  async deleteAuth(id: number): Promise<any> {
    return await this.AuthCenterConfigModel.deleteById(id);
  }

  /**
   * 微信小程序登录，code换取openid
   * @param code 
   */
  async getWxopenid(code: string): Promise<any> {
    const appid = "wxe32d31a9ab3b3da0";
    const secret = "4273158a4f1cab6f3896f581b07ab926";
    const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${secret}&js_code=${code}&grant_type=authorization_code`
    const res = await this.httpService.get(url);
    return res.data || null;
  }


  //        统一授权接口

  /**
   * 根据code 查询配置的授权回调地址信息
   * @param code 
   * @returns 
   */
  async getConfigByCode(code: string): Promise<any> {
    //  查询当前授权回调请求信息
    const authInfo = await this.AuthCenterConfigModel.getDataByCode(code);
    if (!authInfo || !authInfo[0]) throw new httpError.BadRequestError('授权回调信息不存在');
    return authInfo[0];
  }

  /**
   * 获取在职员工的unionid列表
   * @returns 
   */
  async getOnJobUserLists(): Promise<any> {
    let _users = [];
    try{
      const configInfo = await this.JsonConfigModel.getDataByCode('OnJobUser');
      if (configInfo && configInfo.length && configInfo[0].json_data) {
        let _arr = configInfo[0].json_data ? JSON.parse(configInfo[0].json_data) : [];
        for(let i = 0; i < _arr.length; i++){
          _users.push(_arr[i].unionid)
        }
      }
      return _users;
    }catch(e){
      return []
    }
  }
}